import java.lang.reflect.Method;

/**
 * StringType
 * 和char类型不同，字符串类型String是引用类型，我们用双引号"..."表示字符串。一个字符串可以存储0个到任意个字符：
 */
public class StringType {

    public static void main(String[] args) {
        StringType st = new StringType();
        st.defineString();
        st.stringConnect();
        st.multiLineString();
        st.stringNoChange();
        st.stringNoChangeTest();
        st.nullType();
        st.test();
    }
    private void defineString() {
        String s = ""; //空字符串包含0个字符
        String s1 = "A";//包含一个字符
        String s2 = "ABC";//包含3个字符
        String s3 = "中文 ABC";//包含6个字符传,其中一个是空格
        
        System.out.println(s);
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);

        // 因为字符串使用双引号"..."表示开始和结束，那如果字符串本身恰好包含一个"字符怎么表示？例如，"abc"xyz"，编译器就无法判断中间的引号究竟是字符串的一部分还是表示字符串结束。这个时候，我们需要借助转义字符\：
        String s4 = "abc\"xyz"; //转义字符 \
        System.out.println(s4);
        // 注意:转义字符 \ 不能单独使用,后边必须跟要转义的字符
    }

    // Java的编译器对字符串做了特殊照顾，可以使用+连接任意字符串和其他数据类型，这样极大地方便了字符串的处理。
    private void stringConnect() {
        String s1 = "hello";
        String s2 = "world";
        String s3 = s1 + " " + s2 + "!";
        System.out.println(s3); //hello world!

        // 如果用 + 连接字符串和其他数据类型,会将其他数据类型先自动转换成字符串,在连接
        int age = 25;
        String s4 = "age is " + age;
        System.out.println(s4);
    }

    // 多行字符串
    //如果我们要表示多行字符串,使用 + 连接会非常不方便
    private void multiLineString() {
        String s1 = "first line \n" + "second line \n" + "end";
        System.out.println(s1);
    }
    // 从Java 13开始，字符串可以用"""..."""表示多行字符串（Text Blocks）了
    // 由于多行字符串是作为Java 13的预览特性（Preview Language Features）实现的，编译的时候，我们还需要给编译器加上参数：
    // String s2 = """
    //             第一行
    //             第二行
    //             第三行
    //             """;
    // System.out.println(s2);

    //Java字符串不可变
    private void stringNoChange() {
        String s1 = "hello";
        s1 = "world";
        System.out.println(s1); //world
        // 观察输出结果,字符串s1好像变了,其实变得不是字符串,而是变量s的指向
        // 执行String s = "hello";时，JVM虚拟机先创建字符串"hello"，然后，把字符串变量s指向它：
        // 紧接着，执行s = "world";时，JVM虚拟机先创建字符串"world"，然后，把字符串变量s指向它：
        // 原来的字符串"hello"还在，只是我们无法通过变量s访问它而已。因此，字符串的不可变是指字符串内容不可变。
    }

    //测试题
    private void stringNoChangeTest() {
        String s = "hello";
        String t = s;
        s = "world";
        System.out.println(t);//hello
    }

    //空值null
    //引用类型的变量可以指向一个空值null，它表示不存在，即该变量不指向任何对象
    private void nullType() {
        String s1 = null;   //s1是null
        // String s2;          //s2没有赋值,也是null
        String s3 = s1;     //s3也是null
        String s4 = "";     //s4指向空字符串,不是null

        System.out.println(s1);
        // System.out.println(s2);
        System.out.println(s3);
        System.out.println(s4);
        // 注意要区分空值null和空字符串""，空字符串是一个有效的字符串对象，它不等于null。
    }

    //练习
    //请将一组int值视为字符的Unicode编码，然后将它们拼成一个字符串：
    private void test() {
        int a = 72;
        int b = 105;
        int c = 65281;
        String s = "" + (char)a + (char)b + (char)c;
        System.out.println(s); //Hi!

        // String s = "" + (char)a + (char)b + (char)c;
        // 这里的""的意思是定义一个空字符串,后边的 + 就是拼接字符串的操作了.
    }
}